package com.mask.im.server.netty;

import com.mask.im.server.netty.handler.IMChatChannelHandler;
import com.mask.im.server.netty.protocol.MessageProtocolDecoder;
import com.mask.im.server.netty.protocol.MessageProtocolEncoder;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;


/**
 * @author jian
 */
@Log4j2
@Component
public class IMChannelInitializer extends ChannelInitializer<SocketChannel> {


    @Resource
    private IMChatChannelHandler chatHandler;

    // 配置化参数
    @Value("${netty.websocket.path:/ws}")
    private String websocketPath;

    @Value("${netty.http.max-content-length:65536}")
    private int maxContentLength;

    @Value("${netty.idle.read-timeout:30}")
    private int readTimeout;

    @Value("${netty.idle.write-timeout:0}")
    private int writeTimeout;

    @Value("${netty.idle.all-timeout:0}")
    private int allTimeout;

    @Override
    protected void initChannel(SocketChannel socketChannel) {
        try {
            log.debug("初始化通道: {}", socketChannel.remoteAddress());
            // 获取通道的处理器链
            ChannelPipeline pipeline = socketChannel.pipeline();
            // 配置通道选项
            configureChannelOptions(socketChannel);
            pipeline
                    // HTTP编码解码器
                    .addLast("http-codec", new HttpServerCodec())
                    // 大数据流支持
                    .addLast("chunked-writer", new ChunkedWriteHandler())
                    // HTTP聚合器，设置最大内容长度
                    .addLast("http-aggregator", new HttpObjectAggregator(maxContentLength))
                    // WebSocket协议处理器
                    .addLast("websocket-handler", new WebSocketServerProtocolHandler(websocketPath, null, true))
                    // 自定义协议解码器
                    .addLast("message-decoder", new MessageProtocolDecoder())
                    // 自定义协议编码器
                    .addLast("message-encoder", new MessageProtocolEncoder())
                    // 心跳检测
                    .addLast("idle-handler", new IdleStateHandler(readTimeout, writeTimeout, allTimeout))
                    // 业务处理器
                    .addLast("chat-handler", chatHandler);
            log.debug("通道初始化完成: {}", socketChannel.remoteAddress());
        } catch (Exception e) {
            log.error("通道初始化失败: {}", socketChannel.remoteAddress(), e);
            socketChannel.close();
        }

    }

    /**
     * 配置通道选项
     */
    private void configureChannelOptions(SocketChannel socketChannel) {
        // 使用内存池分配器，提高性能
        socketChannel.config().setAllocator(PooledByteBufAllocator.DEFAULT);
        // 设置TCP选项,禁用Nagle算法
        socketChannel.config().setTcpNoDelay(true);
        // 启用TCP keep-alive
        socketChannel.config().setKeepAlive(true);
        // 设置缓冲区大小,32KB
        socketChannel.config().setReceiveBufferSize(32 * 1024);
        //32KB
        socketChannel.config().setSendBufferSize(32 * 1024);
        // 设置连接超时,5秒
        socketChannel.config().setConnectTimeoutMillis(5000);
    }

    /**
     * 初始化异常处理
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("通道初始化异常: {}", ctx.channel().remoteAddress(), cause);
        ctx.close();
    }
}
